package com.echo.boot.design.turing.singleton;

import com.echo.boot.design.turing.singleton.enumsingleton.EnumSingleton;
import com.echo.boot.design.turing.singleton.innerclass.InnerClassSingleton;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * Created with IntelliJ IDEA
 * Created By CQ
 * Date: 2020/7/26
 * Time: 9:47
 */
public class Main {
    public static void main(String[] args) throws Exception {
//        double random = Math.random();
//        for (int i = 0; i < 100; i++) {
//            System.out.println(Math.random());
//
//        }
//        enableSerializable();
//        enumSingletonSerializable();
    }

    static void reflectAttack() throws Exception {
        // 反射攻击 通过反射可以获取calss 文件,动态获取实例对象. InnerClassSinggleton 可以防护
        // 饿汉模式是无法防护的
        Constructor<InnerClassSingleton> constructor = InnerClassSingleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        InnerClassSingleton innerClassSingleton = constructor.newInstance();
    }

    /**
     * 把对象放在文件文件里或redis 怎么保证单例,首先 要实现 Serializable 接口
     * 同时 添加属性 serialVersionUid  如果不加的话 JVM 在序列化的时候自动生成保存在文件中。
     * 反序列的时候 JVM 也会生成一个 uid 和 文件中的uid 比较,这个时候会出现不是同一个对象，无法烦序列化
     */
    static void enableSerializable() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IOException, ClassNotFoundException {

        InnerClassSingleton instance = InnerClassSingleton.getInstance();
        ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("textSerializable"));
        outputStream.writeObject(instance);

        ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("textSerializable"));
        InnerClassSingleton o = (InnerClassSingleton) inputStream.readObject();

        System.out.println(instance == o);


    }

    static void enumSingletonSerializable() throws Exception {
        EnumSingleton instance = EnumSingleton.INSTANCE;
        // 枚举类不需要实现 Serializable 接口,也可以完成序列化
        ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("enumSerializable"));
        outputStream.writeObject(instance);

        ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("enumSerializable"));
        EnumSingleton o = (EnumSingleton) inputStream.readObject();

        System.out.println(instance == o);
    }


}
